/*
 * @Author: chengtianming timmy_cheng@foxmail.com
 * @Date: 2023-11-25 10:36:35
 * @LastEditors: shenya shenya0203@163.com
 * @LastEditTime: 2024-04-25 16:50:09
 * @FilePath: \undefinedd:\YC项目资料\6 佛山照明\7628网关\佛照需求\网关项目需求文档\需求2023112401\udp_server.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <curl/curl.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>

#include "cJSON.h"
#include "fast_conble_define.h"
#include "udp_server.h"
#include "log.h"
#include "fast_conble_func.h"
#include "sql_func.h"
#include "json_data.h"
#include "protocol_data.h"
#include "mqtt_cli.h"

#define MAX_BUFFER_SIZE 1024 + 4
#define MAX_MSG_LEN 1024
#define MAX_ADDR_SIZE 255

/*静态变量*/
static int socketfd = -1;
uint8_t g_mac_addr[ADDR_LEN] = {0};
static char remote_ip[15 + 1] = {};
static int remote_port = 0;
struct sockaddr_in remote_addr;

// 用于传递通信的数组，配合信号量使用
uint8_t reportMsg_buffer[MAX_MSG_LEN] = {0};
uint16_t reportMsg_len = 0;

/*内部函数*/
int UdpSendtoRemote(message_t *package, int package_len)
{
    uint8_t buff[256] = "";
    int ret = sendto(socketfd, package, package_len, 0,
                     (struct sockaddr *)&remote_addr, sizeof(remote_addr));
    if (ret == -1)
    {
        sprintf(buff, "Error sending package[%d]", package->head.type);
        perror(buff);
    }
    printf("package content [ ");
    for (int i = 0; i < package_len; i++)
        printf("%02X ", ((uint8_t *)package)[i]);
    printf("]\n");
    return ret;
}

/**
 * @description: 初始化UDP服务器
 * @param {char *} ip_addr 绑定地址，本地地址
 * @param {uint16_t} port 接受端口
 * @return {*}  成功：句柄
 *              失败：-1
 */
int InitUdpServer(const char *ip_addr, uint16_t port)
{
    struct sockaddr_in serverAddr;

    // 创建套接字
    if ((socketfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("Error creating socket");
        return -1;
    }

    // 设置服务器地址结构
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = (ip_addr != NULL) ? inet_addr(ip_addr) : INADDR_ANY;

    // 绑定套接字到地址和端口
    if (bind(socketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
    {
        perror("Error binding socket");
        close(socketfd);
        return -1;
    }

    log_debug("UDP server listening on port %d...\n", port);

    // 复制主体信息
    GetMacAddress("eth0", g_mac_addr);
    log_debug("MAC [%02X:%02X:%02X:%02X:%02X:%02X]\n",
              g_mac_addr[0], g_mac_addr[1], g_mac_addr[2], g_mac_addr[3], g_mac_addr[4], g_mac_addr[5]);

    return socketfd;
}

/**
 * @description: 关闭UDP服务器并释放资源
 * @return {*}
 */
void DeinitUdpServer(void)
{
    /*关闭socket*/
    close(socketfd);
}

// 获取本机MAC地址的函数
void GetMacAddress(const char *interface, uint8_t *body)
{
    int sockfd;
    struct ifreq ifr;

    // 打开一个套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 设置接口名
    strcpy(ifr.ifr_name, interface); // 替换为你的网络接口名，比如 "eth0" 或 "wlan0"

    // 获取MAC地址
    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1)
    {
        perror("ioctl");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 关闭套接字
    close(sockfd);

    // 将MAC地址的字节拷贝到body中
    memcpy(body, ifr.ifr_hwaddr.sa_data, 6);
}

void UpdateDeviceDevlist(cJSON *json)
{
    FastConbleDevlist devlist;
    cJSON *data_obj = NULL;

    data_obj = cJSON_GetObjectItem(json, "did");
    devlist.did = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "pid");
    devlist.pid = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "devname");
    devlist.devname = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "room");
    devlist.room = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "roomId");
    devlist.roomId = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "devicetypeflag");
    devlist.devicetypeflag = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "ignoreflag");
    devlist.ignoreflag = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "version");
    devlist.version = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "extendInfo");
    devlist.extendInfo = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "terminalid");
    devlist.terminalid = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "aeskey");
    devlist.aeskey = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "shortaddr");
    devlist.shortaddr = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "bletoken");
    devlist.bletoken = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "sdid");
    devlist.sdid = (data_obj != NULL) ? data_obj->valuestring : NULL;

    SqlInsertDevlist(&devlist);
}

void UpdateDeviceRoomlist(cJSON *json)
{
    FastConbleFamilyInfoRoomlist roomlist;
    cJSON *data_obj = NULL;

    data_obj = cJSON_GetObjectItem(json, "roomId");
    roomlist.roomId = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "roomName");
    roomlist.roomName = (data_obj != NULL) ? data_obj->valuestring : NULL;

    SqlInsertFamilyInfoRoomlist(&roomlist);
}

void UpdateDeviceGrouplist(cJSON *json)
{
    FastConbleGroupList grouplist;
    cJSON *data_obj = NULL;

    data_obj = cJSON_GetObjectItem(json, "groupId");
    grouplist.groupId = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "groupName");
    grouplist.groupName = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "roomId");
    grouplist.roomId = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "roomName");
    grouplist.roomName = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "blecatetory");
    grouplist.blecatetory = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "ignoreflag");
    grouplist.ignoreflag = (data_obj != NULL) ? data_obj->valueint : -1;

    SqlInsertGroupList(&grouplist);
}

void UpdateDeviceScenelist(cJSON *json)
{
    if (json == NULL)
    {
        log_warn("Invalid args json[%p] error\n", json);
        return;
    }

    FastConbleSceneList scenelist;
    cJSON *data_obj = NULL;

    data_obj = cJSON_GetObjectItem(json, "name");
    scenelist.name = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "room");
    scenelist.room = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "roomId");
    scenelist.roomId = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "image");
    scenelist.image = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "backColor");
    scenelist.backColor = (data_obj != NULL) ? data_obj->valueint : -1;

    data_obj = cJSON_GetObjectItem(json, "bletoken");
    scenelist.bletoken = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "moduleid");
    scenelist.moduleid = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "ignoreflag");
    scenelist.ignoreflag = (data_obj != NULL) ? data_obj->valueint : -1;

    SqlInsertSceneList(&scenelist);
}

void UpdateDeviceScenelistModuledev(cJSON *json, char *moduleid)
{
    if (json == NULL || moduleid == NULL)
    {
        log_warn("Invalid args json[%p] moduleid[%p] error\n", json, moduleid);
        return;
    }

    FastConbleSceneListModuleDev moduledev;
    cJSON *data_obj = NULL;

    moduledev.moduleid = moduleid;

    data_obj = cJSON_GetObjectItem(json, "sdid");
    moduledev.sdid = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "content");
    moduledev.content = (data_obj != NULL) ? data_obj->valuestring : NULL;

    data_obj = cJSON_GetObjectItem(json, "did");
    moduledev.did = (data_obj != NULL) ? data_obj->valuestring : NULL;

    SqlInsertSceneListModuleDev(&moduledev);
}

int isDatainfoTableUpdateToDate(char *mtag, FastConbleDataInfo *data_info)
{
    int ret = -1;
    if (mtag == NULL || data_info == NULL)
    {
        log_error("Invalid in arg mtag[%p] data_info[%p]", mtag, data_info);
        return ret;
    }

    // 查询当前表中对应mtag的updateTime
    FastConbleDataInfo qry_data_info;
    int sql_ret = SqlQueryDataInfoByMtag(data_info->mtag, &qry_data_info);
    if (sql_ret != 0)
    {
        log_error("Query %s updateTime failed", data_info->mtag);
    }
    else
    {
        log_debug("updateTime[%s] in table", qry_data_info.updateTime);
        log_debug("updateTime[%s] in url", data_info->updateTime);
        // 如果当前数据的updateTime要比表里面的大则更新，否则不更新
        if (strcmp(qry_data_info.updateTime, data_info->updateTime) >= 0)
        {
            ret = 0;
        }
        ret = 1;
    }

    return ret;
}

int UpdateDeviceInfo(cJSON *json)
{
    if (json == NULL)
    {
        log_warn("input args json[%p] error\n", json);
        return -1;
    }

    cJSON *dataArray = cJSON_GetObjectItem(json, "data");
    if (dataArray == NULL || !cJSON_IsArray(dataArray))
    {
        log_error("Error: Unable to find or parse 'data' array\n");
        cJSON_Delete(json);
        return -2;
    }

    // 遍历 "data" 数组，data数组里面一般只有一个{}json对象
    for (int i = 0; i < cJSON_GetArraySize(dataArray); i++)
    {
        // 获取当前 "data" 元素
        cJSON *dataItem = cJSON_GetArrayItem(dataArray, i);
        if (dataItem == NULL || !cJSON_IsObject(dataItem))
        {
            log_error("Error: Unable to parse 'data' item at index %d\n", i);
            continue;
        }

        // 获取 "dataList" 数组
        cJSON *dataListArray = cJSON_GetObjectItem(dataItem, "dataList");

        if (dataListArray == NULL || !cJSON_IsArray(dataListArray))
        {
            log_error("Error: Unable to find or parse 'dataList' array in 'data' item at index %d\n", i);
            continue;
        }

        int data_size = cJSON_GetArraySize(dataListArray);
        // 遍历 "dataList" 数组
        for (int j = 0; j < cJSON_GetArraySize(dataListArray); j++)
        {

            // char out_str[data_size][4096];  //使用自动分配内存
            char *out_str[data_size]; // 无法定义时初始化
            memset(out_str, 0, sizeof(out_str));
            // 获取当前 "dataList" 元素
            cJSON *dataListItem = cJSON_GetArrayItem(dataListArray, j);

            if (dataListItem == NULL || !cJSON_IsObject(dataListItem))
            {
                log_error("Error: Unable to parse 'dataList' item at index %d in 'data' item at index %d\n", j, i);
                continue;
            }

            // char *json_result = cJSON_Print(dataListItem);
            // log_debug("Formatted JSON Object:\n%s\n", json_result);
            // 更新data_info表
            FastConbleDataInfo data_info;
            cJSON *data_mtag = cJSON_GetObjectItem(dataListItem, "mtag");
            data_info.mtag = (data_mtag != NULL) ? data_mtag->valuestring : NULL;

            cJSON *data_validTime = cJSON_GetObjectItem(dataListItem, "validTime");
            data_info.validTime = (data_validTime != NULL) ? data_validTime->valueint : -1;

            // 下面3个不是每个devlist中都有
            cJSON *data_updateTime = cJSON_GetObjectItem(dataListItem, "updateTime");
            data_info.updateTime = (data_updateTime != NULL) ? data_updateTime->valuestring : NULL;

            cJSON *data_devqueryTime = cJSON_GetObjectItem(dataListItem, "devqueryTime");
            data_info.devqueryTime = (data_devqueryTime != NULL) ? data_devqueryTime->valuestring : NULL;

            cJSON *data_familyId = cJSON_GetObjectItem(dataListItem, "familyId");
            data_info.familyId = (data_familyId != NULL) ? data_familyId->valuestring : NULL;

            // 查询表中对应mtag的更新时间和url的更新时间比较
            //  if (isDatainfoTableUpdateToDate(data_info.mtag, &data_info) != 1)
            //          continue;

            // 舍弃数据库
            //  int sql_ret = SqlInsertDataInfo(&data_info);
            //  if (sql_ret != 0)
            //  {
            //      log_error("Failed to update data info sql_ret[%d]\n", sql_ret);
            //      continue;
            //  }

            // 获取 "data" 字符串
            cJSON *dataString = cJSON_GetObjectItem(dataListItem, "data");
            if (dataString == NULL || !cJSON_IsString(dataString))
            {
                log_error("Error: Unable to find or parse 'data' string in 'dataList' item at index %d in 'data' item at index %d\n", j, i);
                continue;
            }

            // 解码并打印 Base64 数据
            // printf("%s\n",(dataString->valuestring));
            out_str[j] = (char *)calloc(strlen(dataString->valuestring), 1);
            base64_decode(dataString->valuestring, strlen(dataString->valuestring), out_str[j]);
            printf("%s\n", out_str[j]);
            printf("%d\n", j);
            printf("------------------------------------------------\n");
            // cJSON *decodedData = cJSON_Parse(out_str[j]);
            // cJSON_ReplaceItemInObject(dataListItem, "data", decodedData);
            // char *json_result = cJSON_Print(dataListItem);
            // log_debug("Formatted JSON Object:\n%s\n", json_result);
            cJSON *dataData = cJSON_GetObjectItem(dataListItem, "data");
            if (dataData == NULL) // 这个的data类型可能是array或object
            {
                log_error("Error: Unable to find or parse 'data' string in 'dataList' item at index %d in 'data' item at index %d", j, i);
                continue;
            }

            /*更新devlist中的信息*/
            if (strcmp(data_info.mtag, "devlist") == 0)
            {
                for (int i = 0; i < cJSON_GetArraySize(dataData); i++)
                {
                    cJSON *dataItem = cJSON_GetArrayItem(dataData, i);
                    if (dataItem == NULL || !cJSON_IsObject(dataItem))
                    {
                        log_error("Error: Unable to parse 'data' item at index %d\n", i);
                        continue;
                    }

                    // char *json_result = cJSON_Print(dataItem);
                    // log_debug("Formatted JSON Object:\n%s\n", json_result);
                    // UpdateDeviceDevlist(dataItem);
                }
                // 这时的out_str[j]对应devlist
                //  printf("devlist test\n");
                //  log_debug("Formatted JSON Object:\n%s\n", out_str[j]);
                devList_get(out_str[j]);
            }
            /*更新familyInfo中的信息*/
            else if (strcmp(data_info.mtag, "familyInfo") == 0)
            {
                cJSON *_dataData = NULL;
                _dataData = cJSON_Parse(out_str[j]); // 与上面的不同，要修改为这个
                cJSON *dataList = cJSON_GetObjectItem(_dataData, "roomlist");
                // printf("Array:%s\n", cJSON_Print(dataData));
                if (dataList == NULL || !cJSON_IsArray(dataList))
                {
                    log_error("Unable to parse 'roomlist'");
                    continue;
                }

                for (int i = 0; i < cJSON_GetArraySize(dataList); i++)
                {
                    cJSON *dataItem = cJSON_GetArrayItem(dataList, i);
                    if (dataItem == NULL || !cJSON_IsObject(dataItem))
                    {
                        log_error("Error: Unable to parse 'data' item at index %d\n", i);
                        continue;
                    }
                    // UpdateDeviceRoomlist(dataItem);  //舍弃数据库
                }
                free(out_str[j]); // 先释放，再指向新内容
                out_str[j] = cJSON_Print(dataList);
                int ret = listJson_get(out_str[j], &roomList_p, &roomList_Json); // 获取列表及json
                // printf("%s\n", cJSON_Print(roomList_Json));
                // printf("%s\n", cJSON_Print(cJSON_GetObjectItemCaseSensitive(roomList_Json, "roomlist")));
                printf("ret room:%d\n", ret);
                cJSON_free(_dataData);
            }
            /*更新grouplist中的信息*/
            else if (strcmp(data_info.mtag, "grouplist") == 0)
            {
                // char *json_result = cJSON_Print(dataData);
                // log_debug("Formatted JSON Object:\n%s\n", json_result);

                for (int i = 0; i < cJSON_GetArraySize(dataData); i++)
                {
                    cJSON *dataItem = cJSON_GetArrayItem(dataData, i);
                    if (dataItem == NULL || !cJSON_IsObject(dataItem))
                    {
                        log_error("Error: Unable to parse 'data' item at index %d\n", i);
                        continue;
                    }
                    // UpdateDeviceGrouplist(dataItem); //舍弃数据库
                }
                int ret = listJson_get(out_str[j], &groupList_p, &groupList_Json); // 获取列表及json
                printf("ret group:%d\n", ret);
            }
            /*更新scenelist中的信息*/
            else if (strcmp(data_info.mtag, "scenelist") == 0)
            {
                for (int i = 0; i < cJSON_GetArraySize(dataData); i++)
                {
                    cJSON *dataItem = cJSON_GetArrayItem(dataData, i);
                    if (dataItem == NULL || !cJSON_IsObject(dataItem))
                    {
                        log_error("Unable to parse 'data' item at index %d", i);
                        continue;
                    }
                    // UpdateDeviceScenelist(dataItem); //舍弃数据库

                    cJSON *moduledev = cJSON_GetObjectItem(dataItem, "moduledev");
                    if (moduledev == NULL || !cJSON_IsArray(moduledev))
                    {
                        log_error("Unable to parse 'moduledev'");
                        continue;
                    }

                    for (int i = 0; i < cJSON_GetArraySize(moduledev); i++)
                    {
                        cJSON *sub_dataItem = cJSON_GetArrayItem(moduledev, i);
                        if (sub_dataItem == NULL || !cJSON_IsObject(sub_dataItem))
                        {
                            log_error("Error: Unable to parse 'moduledev' item at index %d", i);
                            continue;
                        }
                        // char *json_result = cJSON_Print(sub_dataItem);
                        // log_debug("Formatted JSON Object:\n%s\n", json_result);

                        cJSON *moduleid = cJSON_GetObjectItem(dataItem, "moduleid");
                        if (moduleid == NULL)
                        {
                            log_error("Error:Failed to get moduleid[%p]", moduleid);
                        }
                        // UpdateDeviceScenelistModuledev(sub_dataItem, moduleid->valuestring);  //舍弃数据库
                    }
                }
                int ret = listJson_get(out_str[j], &sceneList_p, &sceneList_Json);
                printf("ret scene:%d\n", ret);
                // log_info("%s", out_str[j]);
                // printf("test\n%s\n\n", sceneList_p);
            }

            free(out_str[j]); // 释放内存
        }
    }
}

/**
 * @description: udp数据包解析和处理
 * @return {*}
 */
void *UdpMsgHandleThread(void *args)
{
    int ret = 0;
    char buffer[MAX_BUFFER_SIZE] = {};
    // struct sockaddr_in clientAddr;
    socklen_t addr_len = sizeof(remote_addr);

    /*初始化发送包*/
    // send_message = (message_t *)malloc(sizeof(message_t));
    // send_message->body = (uint8_t *)((uint8_t *)send_message+sizeof(message_head_t));  //转换成单字节长度，不然会默认32位长度
    // printf("send_message->body %p\n", send_message->body);

    int rowCount = 0;
    // int ret = SqlQueryGatawayMacCount(SqlCallbackRowCount, &rowCount);
    // if (ret == 0)
    // {
    //     // 输出查询结果
    //     log_info("Number of records in gateway list: %d", rowCount);
    // }
    // else
    // {
    //     log_error("Failed to query record count.");
    //     exit(-1);
    // }

    // FastConbleGatewayList *gateway_list = NULL;
    // if (rowCount != 0)
    // {
    //     gateway_list = (FastConbleGatewayList *)malloc(sizeof(FastConbleGatewayList) * rowCount);
    //     if (gateway_list == NULL)
    //     {
    //         log_error("fail to malloc buffer for gateway_list");
    //         exit(-1);
    //     }
    //     ret = SqlQueryGatawayMac(SqlCallbackGatewayList, gateway_list);

    //     if (ret == 0)
    //     {
    //         for (int i = 0; i < rowCount; ++i)
    //         {
    //             log_debug("gateway_list[%d] ip[%s] mac[%s]\n", i + 1, gateway_list[i].ip, gateway_list[i].mac);
    //         }
    //     }
    // }

    while (1)
    {
        // 接收数据
        memset(buffer, 0, sizeof(message_t));
        ssize_t recvBytes = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE - 1, 0,
                                     (struct sockaddr *)&remote_addr, &addr_len);
        if (recvBytes == -1)
        {
            perror("Error receiving data");
            break; // 退出循环，或者添加错误处理逻辑
        }

        /*记录客户端的地址*/
        // memcpy(remote_addr, clientAddr, sizeof(struct sockaddr_in));
        // memcpy(remote_ip, inet_ntoa(clientAddr.sin_addr), strlen(inet_ntoa(clientAddr.sin_addr)));
        // remote_port = ntohs(remote_addr.sin_port);
        log_debug("Received from %s:%d: %s\n", inet_ntoa(remote_addr.sin_addr),
                  ntohs(remote_addr.sin_port), buffer);

        /*解析type和seq放到message_t的message_head_t中，数据部分放到message_t的body*/
        // 解析接收到的数据
        message_t received_message;
        memcpy(&received_message, buffer, sizeof(message_t)); // 长度检查

        switch (received_message.head.type)
        {
        case PROBE_REQ:
        {
            log_debug("probe_req\n");
            FastConbleAck(PROBE_ACK, received_message.head.seq);
            break;
        }

        case HEARTBEAT_REQ:
        {
            // log_debug("heartbeat\n");
            FastConbleAck(HEARTBEAT_ACK, received_message.head.seq);

            uint8_t mac_addr[ADDR_LEN] = {0};
            char mac_str[ADDR_LEN * 2 + 1] = {0};
            memcpy(mac_addr, received_message.body, ADDR_LEN);
            snprintf(mac_str, ADDR_LEN * 2 + 1, "%02X%02X%02X%02X%02X%02X",
                     mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

            if (rowCount == 0)
            {
                // mac地址入表
                log_debug("first time receive mac[%s]\n", mac_str);
                FastConbleGatewayList list;
                list.ip = inet_ntoa(remote_addr.sin_addr);
                list.mac = mac_str;
                // ret = SqlInsertGatewayList(&list);
                if (ret != 0)
                {
                    log_warn("failed to insert mac[%s] into table\n", mac_str);
                }
                rowCount++;

                /*url请求*/
                // 暂时注释，不用每次调试时请求
                FastConbleUrlRequest();
            }
#if 0 // 只考虑一个网关
                else
                {
                    //如果上面查询rowCount是0则不执行
                    for (int i = 0; i < rowCount; ++i)
                    {
                        if (gateway_list != NULL)
                        {
                            /*如果mac地址不存在*/
                            if (strncmp(mac_str, gateway_list[i].mac, ADDR_LEN*2+1) != 0)
                            {
                                // mac地址入表
                                log_debug("first time receive mac[%s]\n", mac_str);
                                FastConbleGatewayList list;
                                list.ip = inet_ntoa(remote_addr.sin_addr);
                                list.mac = mac_str;
                                ret = SqlInsertGatewayList(&list);
                                if (ret != 0)
                                {
                                    log_warn("failed to insert mac[%s] into table\n", mac_str);
                                }
                                rowCount++;

                                /*url请求*/
                                FastConbleUrlRequest();
                            }
                        }
                        else
                        {
                            log_warn("gateway_list is NULL\n");
                        }
                    }
                }
#endif

            /*测试url请求*/
            // FastConbleUrlRequest();

            // /*测试短地址控制*/
            // uint8_t ctrl_buff1[6] = {0x81, 0, 0, 0, 0, 0};
            // FastConbleShortAddrControl(1, ctrl_buff1, 6);

            // /*测试场景控制*/
            // uint32_t sen_list[8] = {65542, 65546, 65541, 65544, 65547, 65538, 6, 2};
            // static uint8_t indx1 = 0;
            // FastConbleSceneControl(sen_list[(indx1++)&0x07]);

            // /*测试组控制*/
            // uint8_t ctrl_buff2[6] = {0x81, 0, 0, 0, 0, 0};
            // uint8_t grp_list[3] = {1, 193, 194};
            // static uint8_t indx2 = 0;
            // FastConbleGroupControl(grp_list[(indx2++)&0x03], 0x2ba8, ctrl_buff2, 6);

            // /*测试触发数据上报*/
            // uint8_t mask1[13] = {0};
            // mask1[0] = 1;
            // FastConbleTriggerDataReport(0xff, 01, mask1);

            // /*测试设置临时分组*/
            // uint8_t mask2[13] = {0};
            // mask2[0] = 1;
            // uint16_t cookie =  rand();
            // FastConbleSetTempGroup(230, 1, cookie&0xffff, mask2);

            break;
        }

        /*网关返回URL */
        case URL_ACK:
        {
            log_debug("url_ack\n");
            // log_debug("%s\n",received_message.body);
            // cJSON *json = cJSON_CreateObject();
            cJSON *json;

            int result = HttpGetDeviceInfo(received_message.body, strlen(received_message.body), &json);
            // 使用 cJSON_Print 打印格式化的 JSON 对象
            char *json_result = cJSON_Print(json);
            log_debug("Formatted JSON Object:\n%s\n", json_result);

            if (result < 0)
            {
                log_error("failed to get device info\n");
                break;
            }

            /*url内容解析，base64解析，入表*/
            UpdateDeviceInfo(json);

            // 释放 cJSON 对象
            free(json_result);

            cJSON_Delete(json);
            break;
        }
        // 短地址控制响应
        case SHORT_ADDR_CTRL_ACK:
        {
            log_debug("short_addr_ctrl_ack\n");
        }
        /*网关返回场景控制 */
        case SCENE_CTRL_ACK:
        {
            log_debug("scene_ctrl_ack\n");
            uint16_t data_len = received_message.body[0];
            printf("SCENE CTRL [ %04x %04X ", received_message.head.type, received_message.head.seq);
            for (uint16_t i = 0; i < data_len + 1; i++)
                printf("%02X ", received_message.body[i]);
            printf("]\n");
            break;
        }

        /*网关返回组控制 */
        case GROUP_CTRL_ACK:
        {
            log_debug("group_ctrl_ack, %d\n", received_message.head.seq);
            controlGroupFlag = 0;
            struct timespec req = {0, 800 * 1000000};
            nanosleep(&req, NULL);
            controlResult_Sem_post();
            controlResult_Sem_signal();
            break;
        }

        /*网关数据上报 */
        case DATA_REPORT_REQ:
        {
            /*数据上报格式不对*/
            log_debug("data_report_req\n");

            // 调整输出的字节大小端问题
            uint16_t data_len = received_message.body[0] + 4; // 二进制需要用具体长度，strlen不行

            uint8_t *p = (uint8_t *)&received_message;
            // if ((*(p + 5) & 0xf0) == 0xc0)
            {
                printf("DATA_REPORT_REQ [ ");
                for (uint16_t i = 0; i < data_len + 1; i++)
                {
                    printf("%02X ", *(p + i));
                }
                printf("]\n");
                // reportMsg_send(p, data_len);
                // uint16_t data_len = received_message.body[0];
                memcpy(reportMsg_buffer, p, data_len);
                reportMsg_len = data_len;
                if (reportDevState_syncSem_initialized)
                {
                    sem_post(&reportDevState_syncSem);
                }
            }
            FastConbleAck(DATA_REPORT_ACK, received_message.head.seq);
            // reportData_update(p, data_len);
            break;
        }

        /*网关数据上报 */
        case TRIGGER_DEV_STA_REPORT_ACK:
        {
            log_debug("trigger_dev_sta_report_ack\n");
            break;
        }

        /*网关设置临时分组 */
        case SET_TEMP_GROUP_ACK:
        {
            log_debug("set_temp_group_ack\n");
            FastConbleUrlRequest();
            break;
        }

        default:
        {
            log_debug("no type [%d]\n", received_message.head.type);
            break;
        }
        }
    }

    // /*释放mac数组内存*/
    // if (gateway_list != NULL)
    // {
    //     // 释放数组中每个元素的字符串成员的内存
    //     for (int i = 0; i < rowCount; ++i)
    //     {
    //         free(gateway_list[i].ip);
    //         free(gateway_list[i].mac);
    //     }

    //     // 释放数组的内存
    //     free(gateway_list);
    // }
}

void StartUdpMsgHandle(void)
{
    pthread_t thread;
    pthread_create(&thread, NULL, UdpMsgHandleThread, NULL);
}

/**
 * @description: 生成协议头部
 * @param {uint16_t} type 数据类型
 * @param {uint16_t} seq 序号
 * @return {*} 返回数据头部
 */
message_head_t GenerateHead(uint16_t type, uint16_t seq)
{
    message_head_t head;
    // head.type = htons(type);
    // head.seq = htons(seq);
    head.type = type;
    head.seq = seq;

    return head;
}

/**
 * @description: base64解码
 * @param {char *} in_str base64字符串
 * @param {int} in_len 字符串长度
 * @param {char *} out_str 解码后字符串
 * @return {int} 返回解码后字符串长度
 */

int base64_decode(char *in_str, int in_len, char *out_str)
{
    BIO *b64, *bio;
    BUF_MEM *bptr = NULL;
    int counts;

    int size = 0;

    if (in_str == NULL || out_str == NULL)
        return -1;

    b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

    bio = BIO_new_mem_buf(in_str, in_len);
    bio = BIO_push(b64, bio);

    size = BIO_read(bio, out_str, in_len);
    out_str[size] = '\0';

    BIO_free_all(bio);
    return size;
}

/**
 * @description: 对二进制数据进行base64编码
 * @param {unsigned char*} input 指针
 * @param {int} length 数据长度
 * @return {*} 字符串地址，使用后需要释放内存free
 */
char *base64_encode(const unsigned char *input, int length)
{
    BIO *bmem, *b64;
    BUF_MEM *bptr;

    b64 = BIO_new(BIO_f_base64());
    bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, input, length);
    BIO_flush(b64);
    BIO_get_mem_ptr(b64, &bptr);

    char *buff = (char *)malloc(bptr->length);
    memcpy(buff, bptr->data, bptr->length - 1);
    buff[bptr->length - 1] = 0;

    BIO_free_all(b64);

    return buff;
}

// 回调函数的原型
size_t WriteCallback1(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    // 强制类型转换，获取缓冲区指针
    char *response_buffer = (char *)userp;
    // memcpy(response_buffer,contents,realsize + 1);
    //  确保在追加数据前，缓冲区有足够的空间
    if (strlen(response_buffer) + realsize + 1 <= 8192)
    {
        memcpy(&(response_buffer[strlen(response_buffer)]), contents, realsize);
        response_buffer[strlen(response_buffer) + realsize] = '\0'; // 确保字符串以 null 结尾
    }
    else
    {
        // 处理缓冲区溢出错误，这里可以根据实际情况进行适当处理
        fprintf(stderr, "Response buffer overflow!\n");
    }
    // 直接打印接收到的数据
    // printf("%.*s\n", (int)realsize, (char *)contents);

    return realsize;
}
// 回调函数的原型
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    MemoryStruct *mem = (MemoryStruct *)userp;

    mem->data = realloc(mem->data, mem->size + realsize + 1);
    if (mem->data == NULL)
    {
        fprintf(stderr, "Failed to allocate memory\n");
        return 0;
    }

    memcpy(&(mem->data[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->data[mem->size] = 0;

    return realsize;
}

/**
 * @description: 通过http获取url的内容，并保存到json里面
 * @param {uint8_t} *url
 * @param {uint16_t} url_len
 * @param {void} **json 存放json格式数据
 * @return {*} 成功 0
 *             识别 -1
 */
int HttpGetDeviceInfo(uint8_t *url, uint16_t url_len, cJSON **json)
{
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if (curl)
    {

        // 构建完整的URL，假设url已经分配足够的内存
        char fullUrl[10 * 1024]; // 假设URL不会超过256个字符
        snprintf(fullUrl, sizeof(fullUrl), "https://%s", url);
        log_debug("%s\n", fullUrl);
        // 设置 URL
        curl_easy_setopt(curl, CURLOPT_URL, fullUrl);

        /*设置延时*/
        // curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60L);
        // curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L);

        // 设置写入回调函数
        // FILE *fp = fopen("response.txt", "wb");  // 打开一个文件用于保存响应
        // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        // curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

        // 预先分配一个缓冲区用于保存接收到的数据
        // char response_buffer[8192] = {0}; // 适当的缓冲区大小
        MemoryStruct response_buffer; // 修改为可扩充内存的方案
        response_buffer.data = malloc(1);
        response_buffer.size = 0;
        // 设置写入和解析回调函数
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response_buffer);
        // curl_easy_setopt(curl, CURLOPT_WRITEDATA, json);

        /* set commom option */
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        // curl_easy_setopt(curl, CURLOPT_CAINFO, "./cacert.pem");
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);

        // curl_easy_setopt(curl, CURLOPT_SSLVERSION , 3);

        // curl_easy_setopt (curl, CURLOPT_SSLCERT,"cacert.crt");
        // curl_easy_setopt (curl, CURLOPT_SSLCERTTYPE, "PEM");
        // curl_easy_setopt (curl, CURLOPT_SSLKEY,"client.key");
        // curl_easy_setopt (curl, CURLOPT_SSLKEYTYPE,"PEM");

        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);

        // 执行请求
        res = curl_easy_perform(curl);

        // 检查错误
        if (res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() res[%d] 失败: %s\n", res, curl_easy_strerror(res));
            return -1;
        }

        // int parseResult = parseJsonString((char *)response_buffer, json);
        // if (parseResult != 0) {
        //     fprintf(stderr, "Error parsing JSON\n");
        //     return -1;
        // }
        // 解析 JSON 字符串
        // *json = cJSON_Parse((char *)response_buffer);
        *json = cJSON_Parse((char *)response_buffer.data); // 修改为可扩充内存
        // 使用 cJSON_Print 打印格式化的 JSON 对象
        // char *json_result = cJSON_Print(jsonObject);
        // printf("Formatted JSON Object:\n%s\n", json_result);
        // // 释放 cJSON 对象
        // free(json_result);

        // // 使用 cJSON_Print 打印 JSON 结果
        // char *json_result = cJSON_Print(*json);
        // // 打印结果
        // printf("%s\n", json_result);
        // //释放资源
        // free(json_result);

        /*base64解码*/
        // 获取 "data" 数组

        /*判断获取的url结果*/
        cJSON *dataStatus = cJSON_GetObjectItem(*json, "status");
        if (dataStatus->valueint != 0 || dataStatus == NULL)
        {
            log_warn("url request failed status[%d] dataStatus[%p]\n", dataStatus->valueint, dataStatus);
            return -2;
        }

        // //使用 cJSON_Print 打印格式化的 JSON 对象
        // char *json_result = cJSON_Print(json);
        // printf("Formatted JSON Object:\n%s\n", json_result);
        // // 释放 cJSON 对象
        // free(json_result);

        free(response_buffer.data);
        // 清理CURL资源
        curl_easy_cleanup(curl);

        // 清理全局状态
        curl_global_cleanup();

        return 0; // 成功
    }

    return -1; // 初始化 CURL 失败
}

void UrlRequest_timer_handler()
{
    // printf("Timer expired at %ld\n", (long)si->si_value.sival_int);
    log_debug("%s called\n", __func__);
    FastConbleUrlRequest();
}
// 设置URL更新定时器，30分钟定时一次
#define URLREQUEST_TASK_TIME 30*60
timer_t UrlRequest_timerid;
void timer_handler(int sig, siginfo_t *si, void *uc);
void UrlRequest_timer_create()
{
    struct sigaction sa;
    // 设置信号处理函数
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGRTMIN, &sa, NULL) == -1)
    {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
    // 创建定时器
    struct sigevent sev;
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_int = 2;
    if (timer_create(CLOCK_REALTIME, &sev, &UrlRequest_timerid) == -1)
    {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }
    log_info("UrlRequest timer id:%d", UrlRequest_timerid);
}
void UrlRequest_timer_set()
{
    struct itimerspec its = {{URLREQUEST_TASK_TIME, 0}, {URLREQUEST_TASK_TIME, 0}}; // 定时时间，第一个为间隔时间
    if (timer_settime(UrlRequest_timerid, 0, &its, NULL) == -1)
    {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
}
void UrlRequest_timer_stop()
{
    struct itimerspec its = {{0, 0}, {0, 0}};
    if (timer_settime(UrlRequest_timerid, 0, &its, NULL) == -1)
    {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
}

